<?php
require_once('hellavcr.config.php');
require_once('hellavcr.vars.php');
require_once('classes/HellaController.php');
if($config['twitter']) {
  require_once('classes/twitter.class.php');
  $twitter = new Twitter($config['twitter_username'], $config['twitter_password']);
}
date_default_timezone_set(isset($config['timezone']) ? $config['timezone'] : 'US/Pacific');

set_time_limit(0);

if (isset($_REQUEST['showid']))
  $do_show = $_REQUEST['showid'];
else
  $do_show = false;

$log_fp = null;
  
function print_log($message) {
  global $log_fp;
  
  print $message;
  fwrite($log_fp, $message);

}

function print_ajax($message) {
  global $do_show;
  
  if ($do_show !== false)
    print $message;
}


function process_tv() {
  global $config, $twitter, $do_show, $log_fp;
  
  // make the logs world writable
  $logfile_name = $config['hellavcr_dir'].'logs/hellavcr.'.date('m.d.Y').'.log';
  
  $umask = umask();
  umask(0);
  $log_fp = fopen($logfile_name, 'a+');
  umask($umask);
  
  $shows_added = 0;
  $mail_string = '';
  print_log(date($config['logging']['date_format']) . "processing tv...");
  
  //check to make sure the file exists
  if(file_exists($config['hellavcr_dir'].'tv.xml')) {
  
    //create a SimpleXML object
    $xml = simplexml_load_file($config['hellavcr_dir'].'tv.xml');
    
    $downloaded_something = false;
    $no_update = false;
        
    //loop over each show
    $shows = $xml->xpath('/tv/show');
    foreach($shows as $show) {
    
      if ($do_show != $show->attributes()->id && $do_show !== false)
        continue;
    
      //get info from tvrage
      $show_info = get_show_info($show->name);

      $name = htmlspecialchars_decode($show->name) . ' (' . $GLOBALS['formats'][strval($show->format)] . ', ' . $GLOBALS['languages'][strval($show->language)] . ')';
      print_log("\n".date($config['logging']['date_format']) . $name);
      
      //make sure it has an ID
      if(empty($show->attributes()->id)) {
        $show->addAttribute('id', generate_id());
      }
      
      //make sure it has a downloads node
      if(!$show->downloads) $show->addChild('downloads', '');

      //if we got no info (tvrage is down) then don't update it with blank info, that's dumb
      if (empty($show_info)) {
        print_log("\n".date($config['logging']['date_format'])."   get show info FAILED! (tvrage likely down)");
        continue;
      }
      
      //auto update show name to match tvrage
      if($config['update_show_name'] && trim($show->name) != $show_info['name']) {
        $show->name = $show_info['name'];
        print_log("\n".date($config['logging']['date_format']) . '  name updated to match tvrage: ' . $show->name);
      }

      //update episode URL
      if(!$show->url) $show->addChild('url', $show_info['Show URL']);
      else $show->url = trim($show_info['Show URL']);
      
      //update status
      if(!$show->status) $show->addChild('status', $show_info['Status']);
      else $show->status = htmlspecialchars(trim($show_info['Status']));
      
      //update airtime
      if(!$show->airtime) $show->addChild('airtime', $show_info['Airtime']);
      else $show->airtime = htmlspecialchars(trim($show_info['Airtime']));
      
      //update network
      if(!$show->network) $show->addChild('network', $show_info['Network']);
      else $show->network = htmlspecialchars(trim($show_info['Network']));

      //update year the show started
      if(!$show->year) $show->addChild('year', $show_info['Premiered']);
      else $show->year = htmlspecialchars(trim($show_info['Premiered']));

      // be smarter than tvrage. If it says the next episode is the one we already have downloaded then default to "unknown" until it updates
      $next_ep_info = explode('x', $show_info['Next Episode']['episode']);
      if (intval($next_ep_info[0]) == intval($show->season) && intval($next_ep_info[1]) == intval($show->episode)) {
        $next_info = '';
        $show_info['next_timestamp'] = 0;

      // do things normally as long as we're at least one episode behind
      } else {

        //update next ep
        $air_date = $show_info['Next Episode']['airdate'];
        if(substr_count($air_date, '/') == 2) {
        	$date_parts = explode('/', $air_date);
        	$air_date = date('(l) F j, Y', strtotime($date_parts[1] . ' ' . $date_parts[0] . ' ' . $date_parts[2]));
        }
        $next_info = (strlen(trim($show_info['Next Episode']['episode'])) > 0 ? $show_info['Next Episode']['episode'] . ' - "' . $show_info['Next Episode']['title'] . '" airs ' . $air_date : '');

        //update next timestamp (includes date and time)
        if(strpos($show_info['RFC3339'], 'T:00-') !== false) {
          $time_prefix = '00:00';
          if(strlen($show_info['Airtime']) > 0) {
            $time_parts = explode('at', $show_info['Airtime']);
            $time_prefix = date('H:i', strtotime('today ' . $time_parts[1]));
          }
          $show_info['next_timestamp'] = strtotime(str_replace('T:00-', 'T' . $time_prefix . ':00-', $show_info['RFC3339']));
        }

      }

      //update tv.xml with whatever values we got for next and next_timestamp      
      if(!$show->next) $show->addChild('next', htmlspecialchars(trim($next_info)));
      else $show->next = htmlspecialchars(trim($next_info));
      
      if(!$show->next_timestamp) $show->addChild('next_timestamp', $show_info['next_timestamp']==0?'':$show_info['next_timestamp']);
      else $show->next_timestamp = trim($show_info['next_timestamp']==0?'':$show_info['next_timestamp']);

      //queue up any episodes prior to the last episode (there must be at least 1 aired episode)
      if($show_info['Latest Episode']['episode']) {
        $latest = explode('x', $show_info['Latest Episode']['episode']);
        $latest_season = intval($latest[0]);
        $latest_episode = intval($latest[1]);

        //if season or episode are blank, default to the last episode so shows are downloded moving forward
        if($show->season == '' && $show->episode == '') {
          $show->season = $latest_season;
          $show->episode = $latest_episode;
          
          //special case for a brand new series
          if($latest_season == '1' && strpos($latest_episode, '01') !== false) {
          	$show->episode = 0;
          }
        }
        
        //check on the day of air since tvrage doesn't update 'Latest Episode' until midnight
        if((date('m/d/Y') == date('m/d/Y', $show_info['next_timestamp']) && $show->episode == $latest_episode)) {
          $pre_midnight_check = true;
          $latest_episode = intval($latest_episode) + 1;
        
        // if we're forcing it the automatically check for the next episode regardless of what's going on
        } else if ($do_show !== false) {
            $latest_episode = $show->episode + 1;
        }
        
        print_log("\n".date($config['logging']['date_format']) . '  last episode: ' . $show->season . 'x' . sprintf('%02d', $show->episode));
        $one_ep_behind = ($show->season == $latest_season && $show->episode == $latest_episode - 1);
      
        //loop over all mising episodes
        $current_season = intval($show->season);

        while($current_season <= $latest_season) {
          $current_episode = ($current_season > intval($show->season) ? 1 : intval($show->episode + 1));

          while($current_episode <= $latest_episode || $current_season < $latest_season) {
            $episode_string = $current_season . 'x' . sprintf('%02d', $current_episode);
            $episode_info = get_show_info($show->name, $episode_string);
            
            //episode found, attempt to queue
            if($episode_info['Episode Info']) {
              //search newzbin
              $newzbin_info = false;
              $newzbin_used = false;
              if ($config['newzbin']) {

                // try searching for the correct format first, if we can't find it then try any format if dfa
                $newzbin_info = search_newzbin($show->name, $show->year, $current_season, $current_episode, $show->language, $show->format, $show->url);
                if ($newzbin_info) {
                  $newzbin_used = true;
                  $correct_format = true;
                } else if ($show->dfa == 1 && $show->dfa_waiting != 1) {
                  print_log($config['debug_separator'] . "couldn't find correct format, trying first available");
                  $newzbin_info = search_newzbin($show->name, $show->year, $current_season, $current_episode, $show->language, '', $show->url);
                  if ($newzbin_info) {
                    $newzbin_used = true;
                    $correct_format = false;
                  }
                }
              }

              // try tvnzb
              $tvnzb_used = false;
              if (!$newzbin_used && $config['tvnzb']) {

                // try searching for the correct format first, if we can't find it then try any format if dfa
                $newzbin_info = search_tvnzb($show->name, $current_season, $current_episode, $show->language, $show->format);
                if ($newzbin_info) {
                  $tvnzb_used = true;
                  $correct_format = true;
                } else if ($show->dfa == 1 && $show->dfa_waiting != 1) {
                  print_log($config['debug_separator'] . "couldn't find correct format, trying first available");
                  $newzbin_info = search_tvnzb($show->name, $current_season, $current_episode, $show->language, '');
                  if ($newzbin_info) {
                    $tvnzb_used = true;
                    $correct_format = false;
                  }
                }
              }

              // try tvbinz
              $tvbinz_used = false;
              if (!$newzbin_used && !$tvnzb_used && $config['tvbinz']) {

                // try searching for the correct format first, if we can't find it then try any format if dfa
                $newzbin_info = search_tvbinz($show->name, $current_season, $current_episode, $show->language, $show->format);
                if ($newzbin_info) {
                  $tvbinz_used = true;
                  $correct_format = true;
                } else if ($show->dfa == 1 && $show->dfa_waiting != 1) {
                  print_log($config['debug_separator'] . "couldn't find correct format, trying first available");
                  $newzbin_info = search_tvbinz($show->name, $current_season, $current_episode, $show->language, '');
                  if ($newzbin_info) {
                    $tvbinz_used = true;
                    $correct_format = false;
                  }
                }
              }

              //id found
              $nzb_downloaded = false;
              if($newzbin_info) {
                //double episode found
                if(strpos($newzbin_info['title'], $current_season . 'x' . sprintf('%02d', $current_episode + 1)) !== false) {
                   $current_episode++;
                   $episode_string .= '-' . sprintf('%02d', $current_episode);
                   print_log('double episode found' . $config['debug_separator']);
                }
								
                switch($config['newzbin_handler']) {
                  //move to directory
                  case 'nzb':
                    if ($tvnzb_used || $tvbinz_used)
                      $nzb_downloaded = download_nzb($newzbin_info['id'], $newzbin_info['title']);
                    else
                      $nzb_downloaded = download_nzb($newzbin_info['id']);

                    break;
									
                  //send to hellanzb
                  case 'hellanzb':
                    if ($tvnzb_used || $tvbinz_used)
//                      print_log(" can't use tvnzb/tvbinz and hellanzb together" . $config['debug_separator']);
                      $nzb_downloaded = send_to_hellanzb($newzbin_info['id'], true);
                    else
                      $nzb_downloaded = send_to_hellanzb($newzbin_info['id']);
                    break;

                  //send to sabnzbd
                  case 'sabnzbd':
                    if ($tvnzb_used || $tvbinz_used)
                      $nzb_downloaded = send_to_sabnzbd($newzbin_info['id'], true);
                    else
                      $nzb_downloaded = send_to_sabnzbd($newzbin_info['id']);
                    break;

                }
								
                // no reason not to keep the tv.xml file as up to date as possible. This also prevents problems with concurrent instances
                if ($nzb_downloaded) {
                  $xml_updated = saveXML($xml);
                  print_log("\n".date($config['logging']['date_format']) . 'saving xml file' . $config['debug_separator'] . ($xml_updated ? 'done' : 'FAIL'));
                }

                
                // why was this inside the switch?
                if ($nzb_downloaded && !$tvnzb_used && !$tvbinz_used) $shows_added++;

                //newzbin has a limit of 5 nzb's per minute
                if($shows_added % 5 == 0) {
                   sleep(60);
                }

                // send XBMC update
                if ($nzb_downloaded && $config['xbmc'] && $config['xbmc_host']) {
                  $xbmc_ch = curl_init("http://".$config['xbmc_host']."/xbmcCmds/xbmcHttp?command=ExecBuiltIn&parameter=Notification(Download+Started,".urlencode($show->name)."+".$episode_string.")");
                  curl_setopt($xbmc_ch, CURLOPT_RETURNTRANSFER, 1);
                  curl_setopt($xbmc_ch, CURLOPT_TIMEOUT, 5);
                  $result = curl_exec($xbmc_ch);
                  curl_close($xbmc_ch);
                  print_log($config['debug_separator'].'XBMC notification '.($result ? 'OK':'FAILED'));
                }

                //send twitter update
                if($nzb_downloaded && $config['twitter'] && $twitter) {
                  $prefix = $config['hollers'][@array_rand($config['hollers'])];
                  $status = $twitter->send($prefix . $show->name . ' ' . $episode_string . ' (' . $GLOBALS['formats'][strval($show->format)] . ', ' . $GLOBALS['languages'][strval($show->language)] . ')');
                  print_log($config['debug_separator'] . ($status ? 'tweeted ok' : 'twitter FAILED'));
                }

                //build mail string
                if($nzb_downloaded && $config['mail']) {
                  $mail_string .= $show->name . ' ' . $episode_string . ' (' . $GLOBALS['formats'][strval($show->format)] . ', ' . $GLOBALS['languages'][strval($show->language)] . ")\n";
                }
								
                //save to download history
                if($nzb_downloaded) {

                  $downloaded_something = true;
                
                  // only save it in history if it was the format we want
                  if ($correct_format) {
                    $download_node = $show->downloads->addChild('download', '');
                    $download_node->addChild('episode', $episode_string);
                    $download_node->addChild('timestamp', time());

                    $show->dfa_waiting = 0;
                    if (!$config['dfa_sticky'])
                      $show->dfa = 0;

                  } else {
                    print_log($config['debug_separator'] . 'first available copy has been downloaded, waiting for correct format now');
                    $show->dfa_waiting = 1;
                  }

                }
              }
              else {
                print_log($config['debug_separator'] . "skipping this episode");
              }

              //increment last episode for the show
              if(!$one_ep_behind || ($one_ep_behind && $nzb_downloaded && $correct_format)) {
                $show->season = $current_season;
                $show->episode = $current_episode;
              }
							
              $current_episode++;
            }
            //invalid episode, proceed to next season
            else {
              break;
            }
            
          }
          
          $current_season++;
        }
        
      }
    }
    
    //send email
    if($config['mail'] && $mail_string != '') {
      $mail_sent = mail($config['mail_to'], '[hellaVCR] ' . substr_count($mail_string, "\n") . ' episodes found', "The following episodes have been queued in hellanzb:\n\n" . $mail_string, 'From: hellaVCR <hellaVCR@faketown.com>');
      print_log("\n".date($config['logging']['date_format']) . 'emailing queue' . $config['debug_separator'] . ($mail_sent ? 'done' : 'FAIL')); 
    }

    //write new xml file    
    $xml_updated = saveXML($xml);
    print_log("\n".date($config['logging']['date_format']) . 'saving xml file' . $config['debug_separator'] . ($xml_updated ? 'done' : 'FAIL'));

  }
  //xml file not found
  else {
    print_log("\n".date($config['logging']['date_format']) . 'tv XML (' . $config['hellavcr_dir'].'tv.xml' . ') file not found...make sure to use an absolute path');
  }
  
  print_log("\n");

  print_ajax('||||' . ($downloaded_something ? '1' : '0'));

}

//
function get_show_info($show, $ep = '', $exact = '') {
  global $config;
  $show_info = array();
  
  //no show provided
  if(!$show) return false;

  //get quickinfo from tvrage  
  if($fp = @fopen('http://www.tvrage.com/quickinfo.php?show=' . urlencode($show) . '&ep=' . urlencode($ep) . '&exact=' . urlencode($exact), 'r')) {
  
    //get all info for the show
    while(!feof($fp)) {
      $line = fgets($fp);
      list($prop, $val) = explode('@', $line, 2);
      
      /*
      "Show Name" (Name Of The TV Show)
      "Show URL" (URL from the TV Show On TVrage)
      "Premiered" (Year when the show first premiered)
      "Episode Info" (Information About the chosen episode "&ep=2x04")
      "Episode URL" (URL About the chosen episode "&ep=2x04")
      "Latest Episode" (Information About the Last Episode That aired)
      "Next Episode" (Information About the Next Episode)
      "Status" (Current Status of show)
      "Country" (Country of origin)
      "Classification" (Classification of show)
      "Genres" (Genres of show)
      "Network" (Network On Which it airs)
      "Airtime" (Which day of the week and time it is broadcasted)
      "RFC3339" (raw date/time the next episode will air, blank if nothing scheduled)
      */
      
      switch($prop) {
        case 'Latest Episode':
        case 'Episode Info':
        case 'Next Episode':
          list ($ep, $title, $airdate) = explode('^', $val);
          $val = array(
            'episode' => $ep,
            'title' => $title,
            'airdate' => $airdate
          );
          break;
        case 'RFC3339':
          $show_info['next_timestamp'] = strtotime($val);
          break;
        case 'Show Name':
          $show_info['name'] = trim($val);
          break;
      }
      
      $show_info[$prop] = $val;
    }
    
    //close file pointer
    fclose($fp);
  }
  else {
    return false;
  }
  return $show_info;
}

//
function search_newzbin($show, $year, $season, $episode, $language, $format, $show_url) {
  global $config;
  
  //newzbin info blank
  if(empty($config['newzbin_username']) || empty($config['newzbin_password'])) {
    print date($config['logging']['date_format']) . '  newzbin config values not set!' . $config['debug_separator'];
    return false;
  }

  if ($config['newzbin_strict_searches'])
    $q = '"'.urlencode($show).' - '.$season.'x'.sprintf('%02d', $episode).'" OR "'.urlencode($show).' ('.$year.') - '.$season.'x'.sprintf('%02d', $episode).'"';
  else
    $q = urlencode($show) . '+' . $season . 'x' . sprintf('%02d', $episode);
    
  $q_debug = $show . ' - ' . $season . 'x' . sprintf('%02d', $episode) . ' (' . $GLOBALS['formats'][strval($format)] . ')';
  print_log("\n".date($config['logging']['date_format']) . '  searching newzbin for ' . $q_debug);
  
  //build up params
  $query = array(
    'q=^' . $q,
    'u_v3_retention=' . ($config['ng_retention'] * 24 * 60 * 60),
    'searchaction=Search',
    'fpn=p',
    'category=8',
    'area=-1',
    'u_nfo_posts_only=0',
    'u_url_posts_only=0',
    'u_comment_posts_only=0',
    'sort=ps_edit_date',
    'order=desc',
    'areadone=-1',
    'feed=csv'
  );

  if ($config['newzbin_restrict_urls'])
    $query[] = 'q_url='.urlencode($show_url);
	
  if(!empty($language)) {
    $query[] = 'ps_rb_language=' . $language;
  }
	
  if(!empty($format)) {
    $query[] = 'ps_rb_video_format=' . $format;
  }
	
  //send to newzbin
  if($fp = @fopen('http://v3.newzbin.com/search/?' . implode('&', $query), 'r')) {
    $line = @fgetcsv($fp);
    //var_dump($line);
    //return false;
		
    /*
    0: posted date
    1: nzb id
    2: nzb title
    3: newzbin url
    4: tv url
    5: newsgroup names (separated by +)
    */
		
    //newzbin id found
    if($line[1] > 0) {
      print_log($config['debug_separator'] . 'found nzb ID ' . $line[1]);

      //check that it's the right show by comparing the URL
      if (stristr($line[4], $show_url) !== false) {
        print_log($config['debug_separator'] . 'false positive, skipping');
        return false;
      } else
        return array('id' => $line[1], 'title' => $line[2]);

    }
    //newzbin id not found
    else {
      print_log($config['debug_separator'] . 'nzb ID not found');
      return false;
    }
  }
	
}

// search tvnzb feeds for the show
function search_tvnzb($show, $season, $episode, $language, $format) {

  global $config, $GLOBALS;

  # remove bad characters and replace spaces
  $tmp = str_replace(" ", "\.", $show);
  $good_show = sanitize_string(str_replace("&", "and", $tmp), ":()'");

  $q_debug = stripslashes($good_show) . '.S' . sprintf('%02d', $season) . 'E' . sprintf('%02d', $episode) . '.*' . $GLOBALS['formats'][strval($format)] . '';
  print_log("\n".date($config['logging']['date_format']) . '  searching tvnzb for ' . $q_debug);

  $match_str = "/.*".$good_show.".*\.S".sprintf('%02d', $season)."E".sprintf('%02d', $episode)."\..*".$GLOBALS['formats'][strval($format)]."/i";

  // get the feed
  $feed_xml = simplexml_load_file($config['tvnzb_rss']);

  // search every show
  foreach ($feed_xml->channel[0]->item as $myItem) {

    // it's easiest to just match the nzb name, it has all the info we need
    $found = preg_match($match_str, $myItem->title);

    // if we found it then return the necessary info
    if ($found) {
      print_log($config['debug_separator'] . "found a nzb $myItem->title at $myItem->link");
      return array('id' => $myItem->link, 'title' => $myItem->description);
    }
  }

  print_log($config['debug_separator'] . 'show not found on rss feed from tvnzb.com');
  return false;
}

// search tvbinz feeds for the show
function search_tvbinz($show, $season, $episode, $language, $format) {

  global $config, $GLOBALS;

  # remove bad characters and replace spaces
  $tmp = str_replace(" ", "\.", $show);
  $good_show = sanitize_string(str_replace("&", "and", $tmp), ":()'");

  $q_debug = stripslashes($good_show) . '.S' . sprintf('%02d', $season) . 'E' . sprintf('%02d', $episode) . '.*' . $GLOBALS['formats'][strval($format)] . '';
  print_log("\n".date($config['logging']['date_format']) . '  searching tvbinz for ' . $q_debug);
  
  $match_str = "/.*".$good_show.".*\.S".sprintf('%02d', $season)."E".sprintf('%02d', $episode)."\..*".$GLOBALS['formats'][strval($format)]."/i";

  // get the feed
  $tvbinz_ch = curl_init($config['tvbinz_rss']);
  curl_setopt($tvbinz_ch, CURLOPT_ENCODING, 'gzip');
  curl_setopt($tvbinz_ch, CURLOPT_RETURNTRANSFER, true);
  $tvbinz_result = curl_exec($tvbinz_ch);
  curl_close($tvbinz_ch);

  $feed_xml = simplexml_load_string($tvbinz_result);

  // search every show
  foreach ($feed_xml->channel[0]->item as $myItem) {

    // it's easiest to just match the nzb name, it has all the info we need
    $found = preg_match($match_str, $myItem->title);

    // if we found it then return the necessary info
    if ($found) {
      print_log($config['debug_separator'] . "found a nzb $myItem->title at $myItem->link");
      return array('id' => $myItem->link, 'title' => $myItem->title);
    }
  }

  print_log($config['debug_separator'] . 'show not found on rss feed from tvbinz.com');
  return false;
}


//
function download_nzb($newzbin_id, $tvnzb_name="") {
  global $config, $nzb_headers;
  print_log($config['debug_separator'] . 'downloading nzb' . $config['debug_separator']);

  // use newzbin ID
  if ($tvnzb_name == "") {
  
    $nzb_headers = array();
    $ch = curl_init();
    curl_setopt_array($ch, array(
      CURLOPT_URL => 'http://v3.newzbin.com/api/dnzb/',
      CURLOPT_USERAGENT => 'hellaVCR/' . $config['version'],
      CURLOPT_POST => 1,
      CURLOPT_RETURNTRANSFER => 1,
      CURLOPT_HEADER => 0, 
      CURLOPT_HEADERFUNCTION => 'read_header',
      CURLOPT_POSTFIELDS => 'username=' . $config['newzbin_username'] . '&password=' . $config['newzbin_password'] . '&reportid=' . $newzbin_id
    ));
  
    $raw_nzb = curl_exec($ch);

  // use an URL
  } else {

    $tvnzb_ch = curl_init($newzbin_id);
    curl_setopt($tvnzb_ch, CURLOPT_ENCODING, 'gzip');
    curl_setopt($tvnzb_ch, CURLOPT_RETURNTRANSFER, 1);
    $raw_nzb = curl_exec($tvnzb_ch);
    $info = curl_getinfo($tvnzb_ch);
    $nzb_headers['X-DNZB-RCode'] = $info['http_code'];
    $nzb_headers['X-DNZB-Name'] = $tvnzb_name;
    curl_close($tvnzb_ch);

  }
  
  /*
  [X-DNZB-Name] =>  Eureka - 3x05 - Show Me the Mummy
  [X-DNZB-Category] =>  TV
  [X-DNZB-MoreInfo] =>  http://www.tvrage.com/Eureka/episodes/664264/3x05/
  [X-DNZB-NFO] =>  196018317
  [X-DNZB-RCode] =>  200
  [X-DNZB-RText] =>  OK, NZB content follows
	*/
  
  switch($nzb_headers['X-DNZB-RCode']) {
    case 200:
      $filename = trim($nzb_headers['X-DNZB-Name']);
      $filename = str_replace('/', ' ', $filename);
      $fp_nzb = fopen($config['nzb_queue'] . $filename . '.nzb', 'w');
      $nzb_written = fwrite($fp_nzb, $raw_nzb);
      print_log(($nzb_written ? 'written' : 'FAIL (writing the nzb, check directory permissions)'));

      return $nzb_written;
    case 400:
      print_log('FAIL (400: bad request, please supply all parameters)');
      return false;
    case 401:
      print_log('FAIL (401: unauthorized, check username/password)');
      return false;
    case 402:
      print_log('FAIL (402: premium account required)');
      return false;
    case 404:
      print_log('FAIL (404: data not found)');
      return false;
    case 450:
      //api rate limited exceeded, so wait the required time and try again
      print_log('FAIL (450: too many requests)');
      $wait_parts = explode(' ', $nzb_headers['X-DNZB-RText']);
      print_log($config['debug_separator'] . 'waiting ' . $wait_parts[4] . ' second' . ($wait_parts[4] > 1 ? 's' : '') . $config['debug_separator']);
      sleep($wait_parts[4] + 1);
      download_nzb($newzbin_id);
      return false;
    case 500:
      print_log('FAIL (500: internal server error)');
      return false;
    case 503:
      print_log('FAIL (503: service unavailable, newzbin is down)');
      return false;
    default:
      print_log('FAIL (' . trim($nzb_headers['X-DNZB-RCode']) . ': ' . trim($nzb_headers['X-DNZB-RText']) . ')');
      return false;
  }
  
  return true;
}

function read_header($ch, $string) {
	global $nzb_headers;
	$colon_index = strpos($string, ':');
	$nzb_headers[substr($string, 0, $colon_index)] = substr($string, $colon_index + 1);
	return strlen($string);
}

//
function send_to_hellanzb($newzbin_id, $isURL=false) {
  global $config;
  print_log($config['debug_separator'] . 'sending to hellanzb -- ');
  
  try {
    $hc = new HellaController($config['hellanzb_server'], $config['hellanzb_port'], 'hellanzb', $config['hellanzb_password']);
  }
  //error thrown, probably since hellanzb isn't running
  catch(Exception $e) {
    print_log('hellanzb not running!');
    return false;
  }
  
  //use the hellanzb class to send the id/url
  if ($isURL)
    $hc->enqueueURL($newzbin_id);
  else
    $hc->enqueueNewzbin($newzbin_id);
  
  //check hellanzb log to see if the id was processed successfully
  //--
  
  print_log('sent');
  return true;
}

//
function generate_id() {
  return substr(md5(microtime()), 0, 10);
}

//sanitize a string
function sanitize_string ($string, $badchars) {

  $result_string = "";

  foreach (str_split($string) as $char) {
    if (!strstr($badchars, $char))
      $result_string .= $char;
  }

  return $result_string;
}

//
function saveXML($simplexml) {
  global $config;
  $domDoc = new DomDocument('1.0', 'utf-8');
  $domDoc->formatOutput = true;
  $domDoc->preserveWhiteSpace = false;
  $domDoc->loadXml($simplexml->asXml());
  return file_put_contents($config['hellavcr_dir'].'tv.xml', $domDoc->saveXml());
}

function send_to_sabnzbd($newzbin_id, $isURL = false) {
  global $config;
  print 'sending to sabnzbd' . $config['debug_separator'];

  //set params
  $authString = ((strlen($config['sabnzbd_username']) > 0 && strlen($config['sabnzbd_password']) > 0) ? '&ma_username=' . $config['sabnzbd_username'] . '&ma_password=' . $config['sabnzbd_password'] : '');
  $modeString = ($isURL ? 'addurl' : 'addid');
  $priority = ((isset($config['sabnzbd_0.5']) && $config['sabnzbd_0.5']) ? '&priority=1' : '');

  //make curl call
  $ch = curl_init();
  curl_setopt_array($ch, array(
    CURLOPT_URL => 'http://' . $config['sabnzbd_server'] . ':' . $config['sabnzbd_port'] . '/sabnzbd/api?mode=' . $modeString . $authString . '&cat=' . $config['sabnzbd_category'] . '&pp=3&name=' . urlencode($newzbin_id) . $priority,
    CURLOPT_HEADER => 0
  ));
  $result = curl_exec($ch);
  curl_close($ch);

  print ($result ? 'sent' : 'FAIL (check sabnzbd is running and config values are correct)');
  return $result;
}

##### main call

if(empty($hellavcr_include)) {
  process_tv();
}

?>
